home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZApplication.cpp -- the application object
- *
- *
- *
- *
- *
- * © 1996, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
-
- #include "MacZoop.h"
- #include "ZEventHandler.h"
- #include "ZWindow.h"
-
- #ifdef APPEARANCE_MGR_AWARE
- #include "Appearance.h"
- #endif
-
- #include "ZPrinter.h"
- #include "ZUndoTask.h"
- #include "CursorUtilities.h"
-
-
- // gApplication is the global application object. There is only one, naturally.
-
- ZApplication* gApplication = NULL;
- ZMenuBar* gMenuBar = NULL;
-
- // globals
-
- OSType gAppSignature = 'ZAPP';
- Boolean gIsAColourMac = FALSE;
- tMacInfo gMacInfo;
-
- // static functions used by the application object
-
- static pascal long ZGrowFunc( Size bytesShort );
- static GrowZoneUPP gGZFunc = NewGrowZoneProc( ZGrowFunc );
-
- // comment out the following if you do not want printing support
-
- #define PRINTING_ON
-
- /*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
- ZApplication::ZApplication()
- : ZCommander( NULL )
- {
- long qdFeatures;
- OSErr theErr;
-
- done = FALSE;
- phase = kInitialising;
- zEH = NULL;
- curUndoTask = NULL;
- itsPrinter = NULL;
-
- appResRefNum = CurResFile();
-
- // set initial filetypes list to a zero handle
-
- FailNIL(itsFileTypes = (OSType**) NewHandle(0));
-
- // create the memory shortage fund
-
- FailNIL( shortageFund = NewHandle( kShortageFundSize ));
- memIsShort = FALSE;
- userHasSeenAlert = FALSE;
-
- // check to see if we are running on a colour Mac
-
- theErr = Gestalt( gestaltQuickdrawFeatures, &qdFeatures );
- gMacInfo.supportsColour = ((theErr == noErr) && (qdFeatures & 1));
-
- // check for the drag manager
-
- theErr = Gestalt( gestaltDragMgrAttr, &qdFeatures );
- gMacInfo.hasDragManager = ((theErr == noErr) && (qdFeatures & 1));
-
- // check for a FPU
-
- theErr = Gestalt( gestaltFPUType, &qdFeatures );
- gMacInfo.hasFPU = ((theErr == noErr) && ((qdFeatures & 1) == 0));
-
- // check for applescript
-
- theErr = Gestalt( gestaltAppleEventsAttr, &qdFeatures );
- gMacInfo.hasAppleEvents = ((theErr == noErr) && (qdFeatures & 1));
-
- // check for QuickTime™
-
- theErr = Gestalt( gestaltQuickTimeVersion, &qdFeatures );
- gMacInfo.hasQuickTime = ((theErr == noErr) && (qdFeatures > 0));
-
- // check for ICM
-
- theErr = Gestalt( gestaltCompressionMgr, &qdFeatures );
- gMacInfo.hasImgCompressionMgr = (theErr == noErr);
-
- // check for appearance manager
-
- #ifdef APPEARANCE_MGR_AWARE
- theErr = Gestalt( gestaltAppearanceAttr, &qdFeatures );
- gMacInfo.hasAppearanceMgr = (( theErr == noErr ) && ( qdFeatures & 1 ));
-
- #if __powerc
- if ( gMacInfo.hasAppearanceMgr )
- gMacInfo.hasAppearanceMgr = ((long) CreateRootControl != kUnresolvedCFragSymbolAddress );
- #endif
-
- #else
- gMacInfo.hasAppearanceMgr = FALSE;
-
- #endif
-
- // what is the system version?
-
- theErr = Gestalt( gestaltSystemVersion, &qdFeatures );
- gMacInfo.systemVersion = LoWord( qdFeatures );
-
- // initialise the animating cursors, and set the
- // animated watch cursor going.
-
- AppCursorInit();
- gApplication = this;
- }
-
- /*--------------------------------*** DESTRUCTOR ***---------------------------------*/
-
-
- ZApplication::~ZApplication()
- {
- if ( zEH )
- ForgetObject( zEH );
-
- if ( itsPrinter )
- ForgetObject( itsPrinter );
-
- if ( curUndoTask )
- ForgetObject( curUndoTask );
-
- if ( itsFileTypes )
- DisposeHandle((Handle) itsFileTypes);
-
- StopCursorAnimation();
- }
-
-
- /*--------------------------------*** INITMACZOOP ***---------------------------------*/
- /*
-
- Initialises the application, makes the event handler object and the menubar
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::InitMacZoop( const short numMasterBlocks )
- {
- if ( phase == kInitialising )
- {
- // init the mac toolbox, memory mangler etc.
-
- InitMacApplication( numMasterBlocks );
- SetGrowZone( gGZFunc );
- SetWatchCursor();
-
- // make the event handler object
-
- MakeEventHandler();
-
- // make the clipboard object
-
- MakeClipboard();
-
- // read any prefs that the user may have set up (default does nothing)
-
- ReadPrefs();
-
- // make printer object and initialise menubar
-
- InitMenuBar();
- MakePrinter();
-
- // call user-function as last part of initialisation- default
- // does nothing but can be overridden to do further set up.
-
- StartUp();
-
- // draw the menubar- note that this is not drawn until StartUp completes,
- // since we allow the programmer the flexibility to use StartUp to create
- // dynamic menus, etc. if they want.
-
- DrawMenuBar();
- phase = kRunning;
-
- // the cursor is not reset here- we let the main event loop do that so that if
- // events are handled immediately, the cursor keeps right on animating until
- // the user gets a chance to do anything.
- }
- }
-
- /*-----------------------------*** INITMACAPPLICATION ***-----------------------------*/
- /*
-
- Initialises the mac toolbox and memory manager
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZApplication::InitMacApplication( const short numMasterBlocks )
- {
- // chant the "Macintosh mantra"...
-
- InitGraf( &qd.thePort );
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs( NULL );
-
- // clear out the event queue in case any stray clicks or keypresses are left there
-
- FlushEvents( everyEvent, 0 );
-
- // see if the program can run on this Mac- if not, we show an alert and exit straight away
-
- if (! CheckCanRun())
- {
- StopCursorAnimation();
- Alert( kCantRunAlertID, NULL );
- ExitToShell();
- }
- else
- {
- // give yourself enough memory. For a bigger app, you may need to call MoreMasters a few
- // more times. The parameter to this function sets the number of times MoreMasters is
- // called, defaulting to 8, which gives 8 x 64 = 512 handles.
-
- MaxApplZone();
-
- short n = numMasterBlocks;
-
- while( n-- )
- MoreMasters();
- }
- }
-
- /*--------------------------------*** CHECKCANRUN ***---------------------------------*/
- /*
-
- Examine the machine environment to see if this will run on this Mac. By default, it can
- on System 7 or later.
-
- ----------------------------------------------------------------------------------------*/
-
-
- Boolean ZApplication::CheckCanRun()
- {
- // Returning FALSE will cause the program to
- // immediately show an alert and quit.
-
- // by default, we can run on any Mac with System 7.0 or later.
-
- return( gMacInfo.systemVersion >= 0x0700 );
- }
-
-
- /*----------------------------------*** GETNAME ***-----------------------------------*/
- /*
- Get the user-visible name of the application, as seen in the Finder. This works even if
- the user has renamed the app, since it finds the filename.
- ----------------------------------------------------------------------------------------*/
-
-
- void ZApplication::GetName( Str255 appName )
- {
- StringPtr sp = LMGetCurApName();
- CopyPString( sp, appName );
- }
-
- /*------------------------------------*** RUN ***-------------------------------------*/
- /*
-
- Fetch events and handle them until the user quits
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::Run()
- {
- // runs the show by asking the event object to get events and handle them. This goes on
- // forever until done is set to TRUE.
-
- if ( phase == kRunning )
- {
- while(! done)
- {
- try
- {
- // repeatedly get an event, handle an event
-
- Process1Event();
-
- // deal with the memory shortage situation, if one has arisen as
- // a result of the last event.
-
- CheckLowMemory();
- }
- catch( OSErr theErr )
- {
- // if here, an exception was thrown. If the error was userCanceledErr,
- // the alert is not shown, since the exception is legitimate. Thus for
- // many operations, you need only throw a userCanceledErr exception to
- // simply invoke the cancel.
-
- StopCursorAnimation();
- HandleError( theErr );
-
- // the buck stops here- no exceptions will be thrown beyond this point.
- }
- // stop any animating cursors. This means that a lengthy process need
- // only set the cursor going and can then forget about it. When the
- // app resumes handling events, it will be automatically cancelled.
-
- StopCursorAnimation();
- }
- done = TRUE;
- phase = kQuitting;
- }
- }
-
-
- /*-----------------------------*** CHECKLOWMEMORY ***---------------------------------*/
- /*
- check if a low memory situation has arisen. If so, inform the user and manage the re-
- plenishment of the shortage fund.
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::CheckLowMemory()
- {
- if ( memIsShort )
- {
- // some of the shortage fund was used. Try to replenish it:
-
- memIsShort = FALSE;
-
- Handle temp = NewHandle( kShortageFundSize );
-
- // if that resets memIsShort, then the grow zone func was called, so we
- // are not in the clear yet. However, if the grow zone func wasn't
- // called, then we can safely get rid of that handle and replace it with
- // this one
-
- if ( memIsShort )
- {
- if ( temp )
- DisposeHandle( temp );
-
- // couldn't replenish the fund, so if the user hasn't seen the
- // warning yet, show it now.
-
- if (! userHasSeenAlert)
- {
- StopCursorAnimation();
- Alert( kMemoryLowAlertID, NULL );
- userHasSeenAlert = TRUE;
- }
-
- // if memIsShort is tRUE, it affects UpdateMenus such that New and Open are
- // greyed out. This is an attempt to stop the user creating things that will
- // eat up even more memory. You might want to use the same technique for commands
- // of your own that may allocate lots of memory. For this reason, memIsShort is
- // a public member.
- }
- else
- {
- // fund replenished, so get rid of any remaining fund and replace it
- // with the newly allocated shortage fund.
-
- DisposeHandle( shortageFund );
- shortageFund = temp;
- userHasSeenAlert = FALSE;
- }
- }
- }
-
-
- /*-------------------------------*** HANDLEERROR ***----------------------------------*/
- /*
- display an alert indicating the error (some errors do nothing, likewise noErr is ignored)
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::HandleError( OSErr theErr )
- {
- // handles the error passed by displaying an alert. This is called by the exception
- // handler for the application, but you can call it at any time. Some errors are "silent"
- // in that the exception does not result in a message. These include userCanceled, kSilent
- // Err, and aeEventNotHandled. Override this if you want to handle errors differently.
-
- if ( theErr != userCanceledErr &&
- theErr != kSilentErr &&
- theErr != noErr &&
- theErr != errAEEventNotHandled )
- {
- StringHandle errExpH;
- Str255 errMsgStr;
- Str31 errExplStr;
- Str15 errIDStr;
-
- NumToString( theErr, errIDStr );
-
- // try to build a meaningful error message by looking for an 'Estr'
- // resource with the same iD as the error. If found, this is concatenated
- // onto the generic error stub and displayed. If not found, the default
- // explanation "an error occurred" is used.
-
- GetIndString( errMsgStr, 128, 10 );
-
- errExpH = (StringHandle) GetResource( 'Estr', theErr );
-
- if ( errExpH )
- {
- ConcatPStrings( errMsgStr, *errExpH );
- ReleaseResource((Handle) errExpH );
- }
- else
- {
- GetIndString( errExplStr, 128, 11 );
- ConcatPStrings( errMsgStr, errExplStr );
- }
-
- ParamText( errIDStr, errMsgStr, NULL, NULL );
- Alert( kExceptionAlertID, NULL );
- }
- }
-
-
- /*------------------------------*** PROCESS1EVENT ***---------------------------------*/
- /*
- get an event, dispatch an event, get an event, dispatch...
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::Process1Event()
- {
- zEH->GetAnEvent();
- zEH->DispatchAnEvent();
- }
-
-
-
- /*-----------------------------*** GETCURRENTEVENT ***--------------------------------*/
- /*
- return the current event in progress, with FALSE if it was a null event, else TRUE.
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZApplication::GetCurrentEvent( EventRecord* anEvent )
- {
- zEH->GetLatestEvent( anEvent );
-
- return( anEvent->what != nullEvent );
- }
-
-
- /*--------------------------------*** GETCLICKS ***-----------------------------------*/
- /*
- return the number of clicks counted by the event handler in the same place. Returns 1 for
- single click, 2 for double, 3 for triple, etc.
- ----------------------------------------------------------------------------------------*/
-
- short ZApplication::GetClicks()
- {
- return zEH->GetClicks();
- }
-
-
- /*-------------------------------*** INBACKGROUND ***---------------------------------*/
- /*
- return TRUE if the application is in the background, FALSE in foreground.
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZApplication::InBackground()
- {
- return zEH->InBackground();
- }
-
-
- /*-----------------------------------*** QUIT ***-------------------------------------*/
- /*
-
- close all of the windows. If successful, delete the application and return TRUE
-
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZApplication::Quit()
- {
- if ( phase == kQuitting )
- {
- CloseAll();
-
- // the Quit can be abandoned by resetting <done> to FALSE. If this
- // has not occurred, then truly say goodbye.
-
- if ( done )
- {
- ShutDown();
- ForgetThis();
- }
- }
- return done;
- }
-
-
- /*-------------------------------*** REQUESTQUIT ***----------------------------------*/
- /*
-
- ask the application to quit. This is called by choosing Quit from the File menu, for example.
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZApplication::RequestQuit()
- {
- done = TRUE;
- }
-
- /*----------------------------*** HANDLEAPPLEEVENT ***--------------------------------*/
- /*
- Handle the four required apple events. If you override this to handle your own apple
- events, be sure to call the inherited method for everything else.
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::HandleAppleEvent( AEEventClass aeClass, AEEventID aeID,
- AppleEvent* aeEvt, AppleEvent* reply )
- {
- if ( aeClass == kCoreEventClass )
- {
- FSSpec aFile;
- AEDescList docList;
- long i, n;
- AEKeyword keyWrd;
- DescType retType;
- Size actualSize;
- FInfo fi;
-
- switch ( aeID )
- {
- case kAEOpenApplication:
- #ifndef NO_UNTITLED_STARTUP_WINDOW
- OpenNewWindow();
- #endif
- break;
-
- case kAEOpenDocuments:
- FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));
- FailOSErr( AECountItems( &docList, &n ));
-
- // get each document and open it
- try
- {
- for (i = 1; i <= n; i++)
- {
- FailOSErr( AEGetNthPtr( &docList,
- i,
- typeFSS,
- &keyWrd,
- &retType,
- &aFile,
- sizeof( FSSpec ),
- &actualSize ));
-
- FailOSErr( FSpGetFInfo( &aFile, &fi ));
-
- // open the file into a window and select it
-
- OpenFile( aFile, fi.fdType );
- }
- }
- catch( OSErr err )
- {
- AEDisposeDesc( &docList );
-
- throw err;
- }
- FailOSErr( AEDisposeDesc( &docList ));
- break;
-
- case kAEPrintDocuments:
- FailOSErr( AEGetParamDesc( aeEvt, keyDirectObject, typeAEList, &docList ));
- FailOSErr( AECountItems( &docList, &n ));
-
- // ask the application to show the page setup dialog
-
- DoPageSetup();
-
- // get each document passed by the finder
-
- try
- {
- for (i = 1; i <= n; i++)
- {
- FailOSErr( AEGetNthPtr( &docList,
- i,
- typeFSS,
- &keyWrd,
- &retType,
- &aFile,
- sizeof( FSSpec ),
- &actualSize ));
-
- FailOSErr(FSpGetFInfo( &aFile, &fi ));
-
- // open the file into a window and select it
-
- OpenFile( aFile, fi.fdType );
-
- // update the window (not strictly needed, but looks better)
-
- zEH->HandleWindowUpdate( mostRecent->GetMacWindow());
-
- // ask the application to print the document
-
- DoPrint();
-
- // that done, we can close the window and move on to the next
-
- mostRecent->Close( GetPhase());
- }
- }
- catch( OSErr err )
- {
- AEDisposeDesc( &docList );
-
- throw err;
- }
-
- FailOSErr( AEDisposeDesc( &docList ));
- break;
-
- case kAEQuitApplication:
- RequestQuit();
- break;
-
- default:
- inherited::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
- break;
- }
- }
- else
- inherited::HandleAppleEvent( aeClass, aeID, aeEvt, reply );
- }
-
-
- /*------------------------------*** HANDLECOMMAND ***---------------------------------*/
- /*
-
- Handle commands (menu items) that apply to the application as a whole, like Quit.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::HandleCommand( const long aCmd )
- {
- // handle commands at the application level. This includes quit, new, open, etc.
-
- FSSpec aFile;
- OSType anFType;
-
- switch( aCmd )
- {
- case kCmdAbout:
- AboutBox();
- break;
- case kCmdNew:
- OpenNewWindow(); // open a new "untitled" window
- break;
- case kCmdOpen:
- if (PickFile( &aFile, &anFType )) // choose a file
- OpenFile( aFile, anFType ); // open the file into a window
- break;
- case kCmdQuit:
- RequestQuit(); // the app should now quit
- break;
- case kCmdPageSetup:
- DoPageSetup();
- break;
- case kCmdPrint:
- DoPrint();
- break;
- case kCmdUndo:
- if ( curUndoTask ) // undo item available?
- {
- SetWatchCursor();
- if (curUndoTask->IsUndone()) // undo or redo?
- curUndoTask->Redo(); // redo the task
- else
- curUndoTask->Undo(); // undo the task
- }
- break;
- }
- }
-
-
- /*------------------------------*** HANDLECOMMAND ***---------------------------------*/
-
- void ZApplication::HandleCommand( const short menuID, const short itemID )
- {
- GrafPtr savePort;
- Str255 daName;
-
- if ( menuID == kAppleMenuID &&
- itemID > 2 )
- {
- // open desk accessories.
- GetMenuItemText( GetMenuHandle( menuID ), itemID, daName );
- GetPort( &savePort );
- OpenDeskAcc( daName );
- SetPort( savePort );
- }
- }
-
-
- /*-------------------------------*** UPDATEMENUS ***----------------------------------*/
- /*
-
- enable the menu commands that the app can handle at the moment.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::UpdateMenus()
- {
- // enable the menu commands that pertain to the application. This includes "New",
- // "Quit" and "About" amongst others
-
- // apple menu
-
- gMenuBar->EnableCommand( kCmdAbout );
-
- // file menu
-
- // if memory is currently short, do not enable new or open, since those are the
- // commands that are likely to allocate a lot more memory, which we do not have.
-
- if (! memIsShort)
- {
- gMenuBar->EnableCommand( kCmdNew );
- gMenuBar->EnableCommand( kCmdOpen );
- }
- gMenuBar->EnableCommand( kCmdQuit );
-
- // enable the printing items if there is a printer and the front window
- // supports printing.
-
- if ( itsPrinter )
- {
- gMenuBar->EnableCommand( kCmdPageSetup );
-
- ZWindow* fWindow = GetFrontWindow();
-
- if (fWindow && fWindow->IsPrintable())
- gMenuBar->EnableCommand( kCmdPrint );
- }
-
- // edit:
-
- UpdateUndo();
- }
-
-
- /*-------------------------------*** DOPAGESETUP ***----------------------------------*/
- /*
- handle the Page Setup command
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::DoPageSetup()
- {
- if ( itsPrinter )
- {
- gWindowManager->Deactivate();
- itsPrinter->PageSetUp();
- gWindowManager->Activate();
- }
- }
-
- /*----------------------------------*** DOPRINT ***-----------------------------------*/
- /*
- handle the Print command
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::DoPrint()
- {
- if ( itsPrinter )
- {
- ZWindow* aWindow = GetFrontWindow();
-
- gWindowManager->Deactivate();
- itsPrinter->Print( aWindow );
- gWindowManager->Activate();
- }
- }
-
-
- /*---------------------------------*** ABOUTBOX ***-----------------------------------*/
- /*
- display the application's about box
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::AboutBox()
- {
- gWindowManager->Deactivate();
- (void) Alert( kAboutBoxID, NULL );
- gWindowManager->Activate();
- }
-
-
- /*----------------------------------*** SETTASK ***-----------------------------------*/
- /*
- update the current global undo task
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::SetTask( ZUndoTask* aTask )
- {
- if ( curUndoTask )
- ForgetObject( curUndoTask );
-
- curUndoTask = aTask;
- }
-
- /*--------------------------------*** UPDATEUNDO ***----------------------------------*/
- /*
- update the Undo menu item to reflect the current undo task
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::UpdateUndo()
- {
- Str255 undoMenuStr;
-
- if ( curUndoTask )
- {
- // a task available, so update the undo menu item to the task string.
-
- Str63 taskStr;
-
- if (curUndoTask->IsUndone())
- GetIndString( undoMenuStr, kMiscStrListID, kRedoStrIndex );
- else
- GetIndString( undoMenuStr, kMiscStrListID, kUndoStrIndex );
-
- // add the task name
-
- curUndoTask->GetTaskString( taskStr );
- ConcatPStrings( undoMenuStr, taskStr );
-
- // set the menu item to the task name
-
- gMenuBar->SetCommandText( kCmdUndo, undoMenuStr );
-
- // there is a task, but does it refer to the front window? If not,
- // then do not actually enable the command.
-
- if ((curUndoTask->GetUndoTarget() == GetFrontWindow()) &&
- (curUndoTask->GetUndoTarget() != NULL))
- gMenuBar->EnableCommand( kCmdUndo );
- }
- else
- {
- // if no task, just show a dimmed "Can't Undo"
-
- gMenuBar->SetCommandText( kCmdUndo, kMiscStrListID, kCantUndoStrIndex );
- }
- }
-
-
- /*-------------------------------*** INITMENUBAR ***----------------------------------*/
- /*
- set up the menubar object for managing the main menus
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::InitMenuBar()
- {
- // installs the menu bar. By default, we just install 'MBAR' ID = 128, which means you
- // don't need to override this to get other menus- just create the resources you want.
-
- FailNIL( gMenuBar = new ZMenuBar( kStdMenubarID ));
-
- gMenuBar->InitMenuBar();
- }
-
- /*--------------------------------*** MAKECLIPBOARD ***-------------------------------*/
- /*
-
- Make the clipboard object. By default, this is a ZClipboard.
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::MakeClipboard()
- {
- FailNIL( gClipboard = new ZClipboard());
- }
-
-
- /*------------------------------*** MAKEEVENTHANDLER ***------------------------------*/
- /*
-
- Make the event handler object. By default, this is a ZEventHandler. This also makes the
- window manager, since that is functionally related to the event handler.
- ----------------------------------------------------------------------------------------*/
-
-
- void ZApplication::MakeEventHandler()
- {
- // make the event handler
-
- FailNIL( zEH = new ZEventHandler());
-
- // make the window manager for handling floating windows, etc.
-
- FailNIL( gWindowManager = new ZWindowManager());
-
- // install handlers for the four required events
-
- zEH->InstallApplescriptHandlers();
- }
-
-
- /*--------------------------------*** MAKEPRINTER ***---------------------------------*/
- /*
-
- creates a new printer object for handling the print commands
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::MakePrinter()
- {
- #ifdef PRINTING_ON
-
- FailNIL( itsPrinter = new ZPrinter());
-
- #endif
- }
-
- /*------------------------------*** MAKENEWWINDOW ***---------------------------------*/
- /*
-
- creates a new window object and initialises it. It does not show it yet. Normally you will
- override this method to create your own useful kinds of windows. However, even if you don't
- you'll still get a window that works. Eat your heart out Sprocket!
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::MakeNewWindow()
- {
- FailNIL( mostRecent = new ZWindow( this, kUntitledWindowID ));
-
- try
- {
- mostRecent->InitZWindow();
- }
- catch( OSErr err )
- {
- ForgetObject( mostRecent );
-
- throw err;
- }
- }
-
-
- /*------------------------------*** OPENNEWWINDOW ***---------------------------------*/
- /*
-
- creates a new window object and initialises it. It then shows it and makes it active.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::OpenNewWindow()
- {
- mostRecent = NULL;
-
- MakeNewWindow();
-
- if ( mostRecent )
- {
- gWindowManager->InitiallyPlace( mostRecent );
- mostRecent->Select();
- }
- }
-
-
- /*---------------------------------*** CLOSEALL ***-----------------------------------*/
- /*
-
- closes all of the application's windows. If one refuses to close, this will abort a Quit.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::CloseAll( Boolean closeFloaters )
- {
- // closes all of the windows. Called as part of the quit operation. This also checks
- // for the disableAutoClose flag so that windows don't get closed that deliberately
- // set the flag. The techniques used in this method are necessary so that all windows
- // are iterated over correctly even when some get closed.
-
- ZWindow* zappWindow;
- WindowPeek w;
-
- w = (WindowPeek) FrontWindow();
-
- while( w )
- {
- zappWindow = GetZWindow((WindowPtr) w );
- w = w->nextWindow;
-
- if ( zappWindow &&
- !zappWindow->NoAutoClose() &&
- ( closeFloaters == zappWindow->Floats()) &&
- ! zappWindow->Close( phase ))
- {
- phase = kRunning;
- done = FALSE;
-
- break;
- }
- }
-
- // if we're quitting and the user hasn't cancelled, close all the "uncloseables"
- // so that things are cleaned up properly. Uncloseables can still cancel the
- // quit, though this would be a very strange use of such a window!
-
- if ( phase == kQuitting )
- {
- w = (WindowPeek) FrontWindow();
-
- while( w )
- {
- zappWindow = GetZWindow((WindowPtr) w );
- w = w->nextWindow;
-
- if ( zappWindow &&
- !zappWindow->Close( phase ))
- {
- phase = kRunning;
- done = FALSE;
-
- break;
- }
- }
- }
- }
-
-
- /*------------------------------*** GETFRONTWINDOW ***--------------------------------*/
- /*
-
- returns the active window object, if there is one
-
- ----------------------------------------------------------------------------------------*/
-
- ZWindow* ZApplication::GetFrontWindow()
- {
- return ( gWindowManager->GetTopWindow());
- }
-
-
- /*----------------------------------*** PICKFILE ***----------------------------------*/
- /*
-
- displays the standard file dialog for selecting a file, and returns its filespec.
-
- ----------------------------------------------------------------------------------------*/
-
-
- Boolean ZApplication::PickFile( FSSpec* aFile, OSType* fType )
- {
- // uses standard file to choose a file to open to a window. By default, no files types
- // are added to the list, which we here interpret to mean "show all files".
-
- StandardFileReply aReply;
- short numTypes;
-
- HLock((Handle) itsFileTypes );
- numTypes = GetHandleSize((Handle) itsFileTypes ) / sizeof( OSType );
-
- // if no types in the list, show all of them
-
- if( numTypes <= 0 )
- numTypes = -1;
-
- StopCursorAnimation();
- gWindowManager->Deactivate();
-
- // display the dialog
- StandardGetFile( NULL, numTypes, *itsFileTypes, &aReply );
- HUnlock((Handle) itsFileTypes );
-
- gWindowManager->Activate();
-
- if ( aReply.sfGood )
- {
- *aFile = aReply.sfFile;
- *fType = aReply.sfType;
- return TRUE;
- }
- else
- return FALSE;
-
- }
-
-
- /*----------------------------------*** OPENFILE ***----------------------------------*/
- /*
-
- creates a new window and asks it to open the file. It then shows the window and activates it.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZApplication::OpenFile( const FSSpec& aFile, const OSType fType )
- {
- // opens the file into a new window. This is equivalent to OpenNewWindow, but
- // for when the user chose a file with the Open command
-
- mostRecent = NULL;
-
- SetWatchCursor();
- MakeNewWindow();
-
- // window created, so ask it to open the chosen file
-
- if ( mostRecent )
- {
- try
- {
- mostRecent->SetFile( aFile );
- mostRecent->OpenFile( fType );
- gWindowManager->InitiallyPlace( mostRecent );
- mostRecent->Select();
- }
- catch( OSErr err )
- {
- ForgetObject( mostRecent );
- throw err;
- }
- }
- }
-
-
- /*--------------------------------*** ADDFILETYPE ***---------------------------------*/
- /*
- adds <aType> to the list of types this application will show in the Open dialog. You can
- call this for each type your application can open. This ignores duplicates.
- -----------------------------------------------------------------------------------------*/
-
- void ZApplication::AddFileType( const OSType aType )
- {
- // adds the file type to the list of types, if not already there
-
- short nTypes, i;
-
- nTypes = GetHandleSize((Handle) itsFileTypes ) / sizeof( OSType );
-
- // check that the file type we are adding is unique in the list
-
- for ( i = 0; i < nTypes; i++ )
- {
- if ( (*itsFileTypes)[i] == aType )
- return;
- }
-
- // if we are still here, type is unique, so append it
- // first grow the handle
-
- SetHandleSize((Handle) itsFileTypes, sizeof(OSType) * (nTypes + 1) );
- FailOSErr( MemError() );
-
- // set the new entry
-
- (*itsFileTypes)[nTypes] = aType;
- }
-
-
-
- /*------------------------------*** MEMORYSHORTAGE ***--------------------------------*/
- /*
-
- called from the growzone proc when memory needs to be freed. This releases some or all
- of the shortage fund, but you can override it to make additional sacrifices if need be.
-
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZApplication::MemoryShortage( const Size bytesShort )
- {
- // this is called when the memory manager gets into dire straits. We can free some or all
- // of our emergency fund to satisfy the request. If we succeed, we return TRUE, else FALSE.
-
- Size fundSize = 0;
- Handle gzHandle;
-
- // get the handle the mem manager is dealing with at the moment. This is important since
- // this might be the shortage fund itself. If it is, we can't resize it, so we really
- // are in deep do-do. In this case, we flag memIsShort and hope the user will not ignore
- // the message!
-
- gzHandle = GZSaveHnd();
-
- if ( gzHandle != shortageFund )
- {
- fundSize = GetHandleSize( shortageFund );
-
- // release all or some of the memory to try and satisfy the request
-
- if ( fundSize <= bytesShort )
- SetHandleSize( shortageFund, 0 );
- else
- SetHandleSize( shortageFund, fundSize - bytesShort );
- }
- // flag the shortage so we can inform the user
-
- memIsShort = TRUE;
-
- // did we actually manage to free the requested amount?
-
- return( fundSize > bytesShort );
- }
-
-
- #pragma mark -
- /*---------------------------------*** ZGROWFUNC ***----------------------------------*/
- /*
-
- memory manager callback proc.
- ----------------------------------------------------------------------------------------*/
-
- static pascal long ZGrowFunc( Size bytesShort )
- {
- Boolean bytesFreed;
- Size growBytes;
-
- // call application object to free some memory
-
- bytesFreed = gApplication->MemoryShortage( bytesShort );
-
- // try to compact and purge the memory after the
- // application has done something to free some up.
-
- (void) MaxMem( &growBytes );
-
- return bytesFreed;
- }
-
-
- /******************************************************************************
- CopyPString
-
- Copy a Pascal string
- ******************************************************************************/
-
- void CopyPString( ConstStr255Param srcString, Str255 destString )
- {
- BlockMoveData( srcString, destString, MIN( srcString[0] + 1, 255 ));
- }
-
-
- /******************************************************************************
- ConcatPStrings
-
- Concatenate two Pascal strings by attaching the second string on
- the end of the first string.
- ******************************************************************************/
-
- void ConcatPStrings( Str255 first, ConstStr255Param second )
- {
-
- short charsToCopy;
-
- // Truncate if concatenated string would be longer than 255 chars.
-
- charsToCopy = MIN(second[0], 255 - first[0]);
- BlockMoveData(second + 1, first + first[0] + 1, (long) charsToCopy);
- first[0] += charsToCopy;
- }
-
-
- /*------------------------------*** RUNAPPLICATION ***--------------------------------*/
- /*
- standard function to run the application. Your main() function must make the relevant
- ZApplication object, assign it to gApplication, then call this.
- ----------------------------------------------------------------------------------------*/
-
- void RunApplication()
- {
- if (gApplication)
- {
- gApplication->InitMacZoop(); // initialise the whole kaboodle. This is
- // NOT done by the constructor since you might
- // want to override the initialisation.
- do
- {
- gApplication->Run(); // run the application until the user quits
- }
- while (! gApplication->Quit()); // try to quit
- }
- }
-